package com.spring.nio.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.time.LocalDateTime;

/**
 * @author : pangfuzhong
 * @description netty启动客户端
 * @date : 2021/8/10 11:29
 */
@Slf4j
public class NettyServer {
    private static volatile EventLoopGroup bossEventLoopGroup = new NioEventLoopGroup();//TODO ---> 管理服务端NioServerSocketChannel绑定的NioEventLoop
    private static volatile EventLoopGroup workEventLoopGroup = new NioEventLoopGroup();//TODO ---> 管理对接客户端的NioSocketChannel绑定的NioEventLoop
    public static void startup() {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap
            .group(bossEventLoopGroup, workEventLoopGroup)
            .channel(NioServerSocketChannel.class)
            .childHandler(new GlobalChannelInitializer())
            .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
            /**
             *  解释 Backlog主要是指当ServerSocket还没执行accept时，这个时候的请求会放在os层面的一个队列里，这个队列的大小即为backlog值，这个参数对于大量连接涌入的场景非常重要，
             *      例如服务端重启，所有客户端自动重连，瞬间就会涌入很多连接，如backlog不够大的话，可能会造成客户端接到连接失败的状况，再次重连，结果就会导致服务端一直处理不过来
             *      （当然，客户端重连最好是采用类似tcp的自动退让策略）；
             *
             *  使用建议： backlog的默认值为os对应的net.core.somaxconn，调整backlog队列的大小一定要确认ulimit -n中允许打开的文件数是够的
             * */
            .childOption(ChannelOption.SO_BACKLOG, 1024)
            /**
             * Socket参数，关闭Socket的延迟时间，默认值为-1，表示禁用该功能。
             *   -1表示socket.close()方法立即返回，但OS底层会将发送缓冲区全部发送到对端。
             *   0表示socket.close()方法立即返回，OS放弃发送缓冲区的数据直接向对端发送RST包，对端收到复位错误。
             *   非0整数值表示调用socket.close()方法的线程被阻塞直到延迟时间到或发送缓冲区中的数据发送完毕，若超时，则对端会收到复位错误
             * */
            .childOption(ChannelOption.SO_LINGER, -1)
            //TODO --> 是否启用Nagle算法，改算法将小的碎片数据连接成更大的报文来最小化所发送的报文的数量。
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childOption(ChannelOption.SO_SNDBUF, 512)
            .childOption(ChannelOption.SO_RCVBUF, 512);

        serverBootstrap.bind(new InetSocketAddress("192.168.15.153", 10089)).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                System.out.println("服务端启动成功");
            }
        });
    }
}
